"""
    Defines functions for saving and loading composite resources.
"""

import os
from xml.etree import ElementTree as ET
from .. import debug, resource
from ..error import FormatError
from ..misc import strbool
from ..image import Image, Composite
from .util import get_elem_value
from .surface import load as load_surface
from .image import load as image_load

__all__ = (
    'load'
)

VERSION = '0.01'
    
def load(fileOrPath,convertSurf=False,alphaSurf=False):
    """ Loads a Composite resource.
        
        Opens composite files that meet the version %s image resource file
        specification. (See the docs for more info.)
        
        Can also load surfaces and images as composites with a single frame and
        no offset.
        
        TODO: Allow composites to be loaded from compressed files.
        FIXME: May not properly handle file objects in some cases??
        TODO: Test this function!
    """%VERSION
    
    # See if the composite is really a surface
    try:
        surf = load_surface(fileOrPath,convertSurf,alphaSurf)
        return Composite(images=[surf])
    except (IOError,pygame.error):
        pass
    
    # See if the composite is really an image.
    try:
        image = load_image(fileOrPath)
        return image
    except FormatError:
        pass
    
    debug.message("Loading composite '%s'"%fileOrPath)
    
    # Get the leading path if available
    try:
        head,tail = os.path.split(fileOrPath)
    except (AttributeError,TypeError):
        head = ''
    
    # Start parsing
    tree = ET.parse(fileOrPath)
    root = tree.getroot()
    
    # Verify the version
    vers = root.get('version').strip()
    if vers != VERSION:
        raise FormatError("Bad version number '%s'"%vers)
    
    # Verify the root tag
    if root.tag != 'composite':
        raise FormatError("Image root element tag is not 'composite'.")
    
    # Parse & return the data
    
    return _parse_nested(root,head)

def _parse_nested(root,head=''):
    """ Internal function.
        Used to parse composites and sub-composites.
        Ignores the tag and attributes of the root.
    """
    # Get offset values
    elem = root.find('offset')
    if elem is not None:
        offset = (get_elem_value(elem.find('x'), int, 0),
                  get_elem_value(elem.find('y'), int, 0))
    else:
        offset = (0,0)
    
    # Get default position values
    elem = root.find('pos')
    if elem is not None:
        pos = (get_elem_value(elem.find('x'), int, 0),
               get_elem_value(elem.find('y'), int, 0))
    else:
        pos = (0,0)
    
    # Parse the frames list
    subLoader = {'surface':load_surface, 'image':load_image, 'comp':load}
    frames = []
    framesElem = root.find('frames')
    if framesElem is not None:
        # Parse each frame
        for elem in framesElem:
            # Only use this tag if it is one of the known types
            tag = elem.tag.lower()
            if tag in ('surface','image','comp','frame'):
                # Get basic information
                fOffset = [int(elem.get('x',0)),int(elem.get('y',0))]
                src,ref = elem.get('src',None), elem.get('ref',None)
                # File reference
                if src:
                    # Frames have no type and therefore cannot have loader
                    if tag == 'frame':
                        raise FormatError('Composite `frame` element does not allow `src` attribute.')
                    image = subLoader[tag](os.path.join(head,src),
                                           strbool(elem.get('convert')),
                                           strbool(elem.get('alpha')))
                # Library reference
                elif ref:
                    image = resource.depend(ref, tag if tag != 'frame' else None)
                # Nested composites
                elif tag=='comp':
                    image = _parse_nested(elem,head)
                # Don't know what to do!
                else:
                    raise FormatError("Composite %s frame has no `src` or `ref`."%tag)
                # Add the new image
                frames.append([image,fOffset])
    
    # Create the Composite object
    comp = Composite(pos,offset,frames)
    
    return comp

def _autoload(agent):
    """ Internal function.
        Autoloader for Image resources.
    """
    return load(agent.src,
                 agent.extra['convert'] if 'convert' in agent.extra else False,
                 agent.extra['alpha'] if 'alpha' in agent.extra else False)